<?php
/**
 * 京东jos ECLP沧海系统 供应商SDK
 * @author hjj
 */

namespace App\Service\VendorClient\ShopjdApi;

use App\Model\PssModel\ServiceConfig;
use App\Service\Code\Normal;
use App\Service\BaseService;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;

class ShopEclpClient extends BaseService {

    //供应商编号
    const SUPPLIER_CODE = 'shopjdeclp';

    private $config = [];

    public $apiRoute = [
        "createOrder"       => "jingdong.eclp.ibd.order.declareOrder",
        "cancelOrder"       => "jingdong.eclp.order.cancelOrder",
        "queryGoodsList"    => "jingdong.eclp.goods.queryGoodsInfo",
        "queryGoodsStock"   => "jingdong.eclp.stock.searchShopStock",
        "queryOrder"        => "jingdong.eclp.order.queryOrder",
        "queryOrderCustoms" => "jingdong.eclp.order.queryOrderCustoms"
    ];

    public function __construct($apiBody = []) {
        $this->config = $apiBody;
    }

    /**
     * 创建订单
     * @param array $params
     * @return array|string
     */
    public function createOrder($params = []) {
        $orderInfo   = $params['supplierOrder'];
        $goodsList   = $params['orderGoods'];
        $order       = $params['order'];
        $binfo       = $params['binfo'];
        $companyInfo = $params['companyInfo'];
        $order_sn    = $orderInfo['supplier_dsn'];
        //支付流水号
        $pay_sn = $order['paySerial'] ?? $orderInfo['pay_sn'];
        //订单时间
        $order_time = $orderInfo['cd'] ? date('Y-m-d H:i:s', $orderInfo['cd']) : date('Y-m-d H:i:s', time());
        //支付时间
        $pay_time = isset($order['payTime']) && !empty($order['payTime']) ? date('YmdHis', $order['payTime']) : date('YmdHis', time());
        //运费
        $deliver_money = $orderInfo['deliver_money'] ?? 0.00;
        //下单支付的时候支付信息
        $apply_extends = @json_decode($orderInfo['apply_extends'], true);
        //判断电商平台
        $orderEnterpriseNum = $order['enterpriseNum'] ?? '';
        $enterpriseNum      = isset($apply_extends['enterpriseNum']) && !empty($apply_extends['enterpriseNum']) ? $apply_extends['enterpriseNum'] : $orderEnterpriseNum;
        if (empty($enterpriseNum)) {
            return Normal::returnCode(Normal::FAIL, "电商平台编码不存在");
        }
        $orderEnterpriseName = $order['enterpriseName'] ?? '';
        $enterpriseName      = isset($apply_extends['enterpriseName']) && !empty($apply_extends['enterpriseName']) ? $apply_extends['enterpriseName'] : $orderEnterpriseName;
        if (empty($enterpriseName)) {
            return Normal::returnCode(Normal::FAIL, "电商平台名称不存在");
        }
        //判断支付方式是否存在
        $payCommanyCode = $apply_extends['payCommanyCode'] ?? '';
        $payCommanyCode = $order['payCommanyCode'] ?? $payCommanyCode;
        if (empty($payCommanyCode)) {
            return Normal::returnCode(Normal::FAIL, "支付公司编码：【{$payCommanyCode}】未映射，请联系管理员处理");
        }
        $paymentType = ServiceConfig::instance()->getConfigByEventsValue(self::SUPPLIER_CODE, ServiceConfig::TYPE_PAY, $payCommanyCode);
        if (empty($paymentType)) {
            $paymentType = '1,1';
        }
        $payCommanyName = $apply_extends['payCommanyName'] ?? '';
        $payCommanyName = $order['payCommanyName'] ?? $payCommanyName;
        if (empty($payCommanyName)) {
            return Normal::returnCode(Normal::FAIL, "支付公司编码：【{$payCommanyName}】未映射，请联系管理员处理");
        }
        //获取下单商品信息
        $palceOrderGoods = [];
        $goodsTotalMoney = 0;//商品金额
        $way_tax_fee     = 0;//税费
        $totalWeight     = '0';//毛重
        $totalNetWeight  = '0';//净重
        foreach ($goodsList as $key => $item) {
            $price     = $item['price'];
            $weight    = $item['weight'];
            $netWeight = $item['net_weight'];
            $spec_num  = $item['spec_num'];
            $quantity  = $item['quantity'];
            $buyNum    = $spec_num * $quantity;
            $tax_rate  = bcadd('1', (string)$item['tax_rate'], 4);
            //单个商品的含税单价
            $singlePrice = bcdiv((string)$price, (string)$spec_num, 3);
            //单个商品的不含税单价
            $goodsPrice      = bcdiv((string)$price, (string)$tax_rate, 3);
            $goodsPrice      = bcdiv((string)$goodsPrice, (string)$spec_num, 3);
            $goodsPrice      = bcmul((string)$goodsPrice, (string)100, 1);
            $goodsPrice      = bcdiv((string)ceil($goodsPrice), 100, 2);
            $goodsTotalPrice = bcmul((string)$goodsPrice, (string)$buyNum, 2);
            //商品关税当前币种最小单位（分）
            $goodsCustomsTax   = bcsub((string)$singlePrice, (string)$goodsPrice, 2);
            $taxAll            = bcmul((string)$goodsCustomsTax, (string)$buyNum, 2);
            $goodsInfo         = [
                'gnum'       => ($key + 1),//商品序号,必须为整数,从1开始
                'isvGoodsNo' => $item['supplier_skucode'],//商家商品编码,商家系统的商品编码, 长度不超过50
                'spGoodsNo'  => $item['supplier_skucode'],//销售平台商品编码,与商家商品编码保持一致,长度不超过50
                'quantity'   => (int)$buyNum,//数量,必须大于0
                'price'      => $goodsPrice,//单价,不能为空，不能为0,(如果有满减或者买几送几的优惠活动，需要商家自行将优惠金额按订单中的SKU货值比例分摊到每个商品的单价里（price）。)
            ];
            $palceOrderGoods[] = $goodsInfo;
            $goodsTotalMoney   = bcadd((string)$goodsTotalMoney, (string)$goodsTotalPrice, 2);
            $way_tax_fee       = bcadd((string)$way_tax_fee, (string)$taxAll, 2);
            $totalWeight       = bcadd($totalWeight, bcmul($weight, $buyNum, 4), 4);
            $totalNetWeight    = bcadd($totalNetWeight, bcmul($netWeight, $buyNum, 4), 4);
        }
        //订单总价（商品总额 + 税费 + 运费）
        $totalMoney = bcadd((string)$goodsTotalMoney, (string)$deliver_money, 2);
        $totalMoney = bcadd((string)$totalMoney, (string)$way_tax_fee, 2);
        //用户实际支付金额
        $real_total_money = $orderInfo['real_total_money'];
        //订单优惠金额
        $discount_money = bcsub((string)$totalMoney, (string)$real_total_money, 2);
        //推送数据
        $requestParam = [
            'customsOrder' => [
                'isvUUID'                 => $order_sn,//商家订单号（作为商家订单生产出库的唯一标识，同商家进行支付时调支付企业的唯一订单标识；如果存在拆单则传子订单号）
                'isvSource'               => $this->config['isvSource'],//ISV来源编号
                'platformId'              => $this->config['platformId'],//三方平台编号
                'platformName'            => $this->config['platformName'],//三方平台名称
                'platformType'            => '1',//销售平台类型（填1），1-电商平台；2-商家系统
                'spSoNo'                  => $order_sn,//销售平台订单号（填写商家订单号,如果存在拆单则填子单号）
                'deptNo'                  => $this->config['deptNo'],//事业部编号
                'inJdwms'                 => '1',//是否入京仓（填数字），0-否；1-入京仓
                'salesPlatformCreateTime' => $order_time,//订单创建时间(当前时间)，格式为：yyyy-mm-dd HH:mm:ss
                'consigneeName'           => $orderInfo['receive_name'],//收货人姓名
                'consigneeMobile'         => $orderInfo['recveive_phone'],//收货人手机(收件人电话、手机至少有一个不为空)
                'consigneeAddress'        => $orderInfo['province'] . $orderInfo['city'] . $orderInfo['district'] . $orderInfo['receive_address'],//收货人地址（需包含省、市、区前三级地址）
                'consigneeCountry'        => '142',//收货人所在国家(地区)代码（中国，填：142）
                'addressProvince'         => $orderInfo['province'],//收货地址-省名称
                'addressCity'             => $orderInfo['city'],//收货地址-市名称
                'addressCounty'           => $orderInfo['district'],//收货地址-县名称
                'declareOrder'            => '2',//是否申报订单（填数字），1-是；2-否
                'ccProvider'              => $this->config['ccProvider'],//清关服务商编码
                'ccProviderName'          => $this->config['ccProviderName'],//清关服务商名称
                'postType'                => 'I',//电商平台的订单类型, I-进口商品订单；E-出口商品订单
                'pattern'                 => $this->config['pattern'],//跨境业务模式(保税备货=beihuo，保税直邮=zhiyou，个人快件=grkuaijian，邮政=youzheng),
                'customs'                 => $this->config['customs'],//保税区编码
                'warehouseNo'             => $this->config['warehouseNo'],//京东仓库编号
                'ebpCode'                 => $enterpriseNum,//电商平台代码(海关10位编码)
                'ebpName'                 => $enterpriseName,//电商平台名称(暂不使用)
                'discount'                => (float)$discount_money,//优惠券减免金额（只填写优惠券减免金额，无优惠则填0）,(如果有满减或者买几送几的优惠活动，需要商家自行将优惠金额按订单中的SKU货值比例分摊到订单中每个商品的单价里（price）。)
                'discountNote'            => $discount_money > 0 ? '优惠金额' : '',//优惠说明(如果有优惠减免金额，则需附上优惠说明),优惠减免金额大于0时必填
                'istax'                   => '0',//是否包税（填数字）,0-包税；1-不包税
                'taxTotal'                => $way_tax_fee,//税费(按照货款金额计算的税款，无则为0
                'freight'                 => $deliver_money,//运费(货物运输费用，如果商家使用京东快递并进行月结则传0)
                'goodsValue'              => $goodsTotalMoney,//商品价格(商品货款总和，不含任何优惠满减，不含运费；计算公式： goodsValue（商品价格）=price（商品金额）*quantity（商品数量）)
                'weight'                  => (float)(bcdiv($totalWeight, '1000', 4)),//订单总毛重(订单中所有商品的毛重加和，单位为千克)
                'netWeight'               => (float)(bcdiv($totalNetWeight, '1000', 4)),//订单总净重(订单中所有商品的净重加和，单位为千克)
                'buyerRegNo'              => $orderInfo['buyer_phone'],//订购人注册号(订购人在商家平台的用户id，user pin)
                'buyerPhone'              => $orderInfo['buyer_phone'],//订购人电话,长度不超过50
                'buyerName'               => $orderInfo['buyer_realname'],//订购人姓名（海关监管的对象，需要对个人消费额度和实名认证进行管控）
                'buyerIdType'             => '1',//订购人证件类型（填数字），1-身份证；2-其它
                'buyerIdNumber'           => $orderInfo['buyer_idcard'],//订购人证件号码,
                'senderName'              => $this->config['senderName'],//发件人名称,
                'senderCompanyName'       => $this->config['senderCompanyName'],//发件方公司名称,
                'senderCountry'           => $this->config['senderCountry'],//发件地国家,
                'senderZip'               => $this->config['senderZip'],//发件地邮编,
                'senderCity'              => $this->config['senderCity'],//发件地城市,
                'senderProvince'          => $this->config['senderProvince'],//发件地省/州名,
                'senderTel'               => $this->config['senderTel'],//发件人电话,
                'senderAddr'              => $this->config['customs'],//发件人地址,
                'declarePaymentList'      => '2',//是否申报支付单（填数字）,1-是;2-否,
                'paymentType'             => $paymentType,//支付方式（1.网银在线 2.财付通；格式举例：如果是网银在线填写1,1 ；如果是财付通填写2,1； 当declarePaymentList=2时此值填写1,1；其中的逗号为英文逗号。 注意：如果在网银在现和财付通又多个商户号请咨询
                'payCode'                 => $payCommanyCode,//支付企业代码
                'payName'                 => $payCommanyName,//支付企业名称
                'payTransactionId'        => $order['paySerial'] ?? $apply_extends['paySerial'],//支付流水号
                'currency'                => '142',//支付币制(默认填142)
                'paymentConfirmTime'      => $pay_time,//支付时间(yyyyMMddHHmmss),长度位14位
                'shouldPay'               => $real_total_money,//实际支付金额
                'declareWaybill'          => '1',//是否申报运单（填数字），1-是； 2-否
                'logisticsCode'           => 'CYS0000010',//物流企业代码(物流企业在京东系统中的编号，目前只支持京东物流，填：CYS0000010)
                'logisticsName'           => '京东物流',//物流企业名称（请填：京东物流）
                'packNo'                  => 1,//包裹数(固定传1)
                'isDelivery'              => 0,//是否货到付款(0:否,1:是)，（目前不支持货到付款，请填0）
                'insuredFee'              => 0,//保价费用，如果没有保价，请填0
                'shopNo'                  => $this->config['shopNo'],//店铺编号,JD运营或者销售支持反馈给商家字段信息表中提供
                'isSupervise'             => 2,//是否代监管支付（填数字）：1-是 2-否，当跨境业务模式(pattern)=zhiyou或beihuo时必填
            ],
            'goodsList'    => $palceOrderGoods
        ];

        // echo json_encode($requestParam, 320);die;
        $data = [
            'method' => $this->apiRoute['createOrder'],
            // 'method' => 'jingdong.eclp.ibd.order.declareOrder',
            'data'   => $requestParam,
            'tag'    => __FUNCTION__,
        ];
        $res  = $this->execute($data);
        if ($res['code'] == Normal::SUC) {
            return Normal::returnCode(Normal::SUC, "推送订单成功", [
                'thirdpart_order_sn' => $res['data']['eclpSoNo'],
            ]);
        }
        return $res;
    }

    /**
     * 取消订单
     * @param $params
     * @return array|string
     */
    public function cancelOrder($params = []) {
        $data = [
            'method' => $this->apiRoute['cancelOrder'],
            // 'method' => 'jingdong.eclp.order.cancelOrder',
            'data'   => [
                "eclpSoNo" => $params['supplierOrder']['thirdpart_order_sn']
            ],
            'tag'    => __FUNCTION__,
        ];
        return $this->execute($data);
    }

    /**
     * 查询商品列表
     * @param $params
     * @return array|string
     */
    public function queryGoodsList($params = []) {
        $data = [
            'method'  => $this->apiRoute['queryGoodsList'],
            // 'method'  => 'jingdong.eclp.goods.queryGoodsRecord',
            'data'    => [
                'deptNo'   => $this->config['deptNo'],//事业部编码 (长度：50)
                'pageNo'   => $params['page'],//查询页码(长度4)
                'pageSize' => $params['limit'] ?? 10,//查询最大条数，最多1000条(长度:1000)
            ],
            'tag'     => __FUNCTION__,
            'is_task' => false,//命令行里面不能使用多线程task
        ];
        $res  = $this->execute($data);
        if ($res['code'] == Normal::SUC) {
            if (!isset($res['data']['goodsRecordQueryResult']['goodsRecordList'])) {
                return Normal::returnCode(Normal::FAIL, "备案商品数据为空");
            }
            $pageData = $res['data']['goodsRecordQueryResult']['goodsRecordList'];
            foreach ($pageData as &$item) {
                $stockRes          = $this->queryGoodsStock(['goodsNo' => $item['goodsNo']]);
                $item['stockInfo'] = $stockRes['data'];
                unset($item);
            }
            return Normal::returnCode(Normal::SUC, "获取成功", [
                'total' => count($pageData),
                'list'  => $pageData,
            ]);
        }
        return $res;
    }

    /**
     * 查询商品库存
     * @param $params
     * @return array|string
     */
    public function queryGoodsStock($params = []) {
        $data = [
            'method'  => $this->apiRoute['queryGoodsStock'],
            // 'method'  => 'jingdong.eclp.stock.searchShopStock',
            'data'    => [
                'requestId'  => uuid4(),//请求编号；长度50；备注：唯一标识;
                'deptNo'     => $this->config['deptNo'],//事业部编码 (长度：50)
                'shopNo'     => $this->config['shopNo'],//店铺编码；长度50
                // 'warehouseNo' => $this->config['shopNo'],//京东库房编号；长度50
                'goodsNo'    => $params['goodsNo'],//事业部商品编号；长度50
                'pageSize'   => 1000,//每页条数据；最大1000
                'pageNumber' => 1,//页码；最小为1
            ],
            'tag'     => __FUNCTION__,
            'is_task' => false,//命令行里面不能使用多线程task
        ];
        $res  = $this->execute($data);
        if ($res['code'] == Normal::SUC) {
            // echo json_encode($res['data'], 320);die;
            if (!isset($res['data']['shopStockSearchResponse']['data'])) {
                return Normal::returnCode(Normal::FAIL, "备案商品数据为空");
            }
            return Normal::returnCode(Normal::SUC, "获取成功", $res['data']['shopStockSearchResponse']['data']);
        }
        return $res;
    }

    /**
     * 查询订单物流信息
     * 先查询订单详情拿到isvUUID  在用isvUUID去查询申报清关状态
     * @param $params
     * @return array|string
     */
    public function queryOrderExpress($params = []) {
        $data = [
            'method' => $this->apiRoute['queryOrder'],
            'data'   => [
                'eclpSoNo' => $params['thirdpart_order_sn'],//开放平台出库单号
            ],
            'tag'    => 'queryOrder',
        ];
        $res  = $this->execute($data);
        if ($res['code'] == Normal::SUC) {
            // echo json_encode($res['data'], 320);die;
            if (!isset($res['data']['queryorder_result']) || empty($res['data']['queryorder_result'])) {
                return Normal::returnCode(Normal::FAIL, "订单详情不存在");
            }
            $customsData = [
                'method' => $this->apiRoute['queryOrderCustoms'],
                'data'   => [
                    'deptNo'    => $this->config['deptNo'],//事业部编码 (长度：50)
                    'isvUUID'   => $res['data']['queryorder_result']['isvUUID'],
                    'pageNo'    => 1,//页码
                    'pageSize'  => 20,//每页记录数
                    'startDate' => date('Y-m-d H:i:s', $params['cd']),//起始时间
                    'endDate'   => date('Y-m-d H:i:s'),//结束时间
                ],
                'tag'    => 'queryOrderCustoms',
            ];
            $cusRes      = $this->execute($customsData);
            if ($cusRes['code'] != Normal::SUC) {
                return Normal::returnCode(Normal::FAIL, "查询申报结果失败【{$cusRes['msg']}】");
            }
            if (!isset($cusRes['data']['queryordercustoms_result']) || empty($cusRes['data']['queryordercustoms_result'])) {
                return Normal::returnCode(Normal::FAIL, "查询申报结果为空");
            }
            $customsArr = reset($cusRes['data']['queryordercustoms_result']);
            //清关结果(申报中=1、清关成功=2、清关失败=3、失败=4、赤道校验失败=5)
            if ($customsArr['result'] != 2) {
                return Normal::returnCode(Normal::FAIL, "清关中或清关失败", ['exception' => "申报结果【{$customsArr['message']}】"]);
            }
            $expressName = $res['data']['queryorder_result']['shipperName'];
            $expressNo   = $res['data']['queryorder_result']['wayBill'];
            if (empty($expressName) || empty($expressNo)) {
                return Normal::returnCode(Normal::FAIL, "订单未发货", ['exception' => "订单未发货"]);
            }
            return Normal::returnCode(Normal::SUC, "已发货", ['expressName' => $expressName, 'expressNo' => $expressNo]);
        }
        return Normal::returnCode(Normal::FAIL, $res['msg']);
    }

    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute($params = []) {
        $sysParams["app_key"]           = $this->config['appKey'];
        $sysParams["v"]                 = $this->config['version'];
        $sysParams["method"]            = $params['method'];
        $sysParams["timestamp"]         = date("Y-m-d H:i:s");
        $sysParams["access_token"]      = $this->config['accessToken'];
        $sysParams["format"]            = $this->config['format'];
        $apiParams                      = $this->getApiParas($params['data']);
        $sysParams['360buy_param_json'] = $apiParams;
        $sysParams["sign"]              = $this->generateSign($sysParams);
        $requestUrl                     = $this->config['baseUrl'] . "?";
        $arr                            = [];
        foreach ($sysParams as $sysParamKey => $sysParamValue) {
            $arr[] = "$sysParamKey=" . urlencode($sysParamValue);
        }
        $requestUrl = $requestUrl . implode("&", $arr);
        $parameter  = [
            [
                'tag'    => self::SUPPLIER_CODE . '_' . $params['tag'],
                'uid'    => IdService::instance()->getOtherID(),
                'url'    => $requestUrl,
                'data'   => $params['data'],
                'method' => 'get',
                'format' => 'form-data',
                'header' => [],
            ],
        ];
        if (isset($params['is_task']) && $params['is_task'] === false) {
            $resTask = TaskWorker::instance()->addTask($parameter, 'handleDiableTask');
        } else {
            $resTask = TaskWorker::instance()->addTask($parameter);
        }
        $resTask = current($resTask);
        $result  = @json_decode($resTask['response']['result'], true);
        $sucStr  = str_replace('.', "_", $params['method']) . '_response';
        if (isset($result[$sucStr])) {
            return Normal::returnCode(Normal::SUC, "请求成功", $result[$sucStr]);
        }
        //这里处理京东的bug
        $sucStr = str_replace('.', "_", $params['method']) . '_responce';
        if (isset($result[$sucStr])) {
            return Normal::returnCode(Normal::SUC, "请求成功", $result[$sucStr]);
        }
        $msg = $result['error_response']['zh_desc'] ?? '请求失败';
        return Normal::returnCode(Normal::FAIL, $msg);
    }

    /**
     * 签名计算
     */
    protected function generateSign($params) {
        ksort($params);
        $stringToBeSigned = $this->config['appSecret'];
        foreach ($params as $k => $v) {
            if ("@" != substr($v, 0, 1)) {
                $stringToBeSigned .= "$k$v";
            }
        }
        unset($k, $v);
        $stringToBeSigned .= $this->config['appSecret'];
        return strtoupper(md5($stringToBeSigned));
    }

    /**
     * 获取应用参数
     */
    protected function getApiParas($apiParas) {
        if (empty($apiParas)) {
            return "{}";
        }
        return json_encode($apiParas);
    }

}